import java.util.TreeSet;
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.HashSet;

/**
 *
 * @author Zuzana Krejcova
 */
public abstract class EliminaceJednoduchychP
{
    static Object[] transformuj(Gramatika g)
    {
        TreeMap<String, TreeSet<String>> mnozinaMnozinNetermu = new TreeMap();
        TreeSet<String> pomNetermy = new TreeSet();
        //konstrukce mnozin
        for (String neterm : g.neterminaly)
        {
            mnozinaMnozinNetermu.put(neterm, new TreeSet());
            TreeSet<String> netermy = mnozinaMnozinNetermu.get(neterm);
            netermy.add(neterm);
            while (!pomNetermy.equals(netermy))
            {
                pomNetermy.addAll(netermy);
                netermy.addAll(jednoduche(g, pomNetermy));
            }
            pomNetermy.clear();
        }
        //vlastni eliminace jednoduchych pravidel
        TreeMap<String,HashSet<ArrayList<String>>> novaPravidla = new TreeMap();
        for (String neterm : g.pravidla.keySet()) //vyberu si konkretni radek puvodnich pravidel, tedy neterminal
        {
            HashSet<ArrayList<String>> pravaStrana = new HashSet();
            for (ArrayList<String> pravidlo : g.pravidla.get(neterm)) //a najdu si vsechna nejednoducha pravidla
            {
                if ((pravidlo.size() > 1)
                   || (g.terminaly.contains(pravidlo.get(0)))
                   || (pravidlo.get(0).equals("\u03B5")))
                    pravaStrana.add(pravidlo);
            }
            for (String klic : mnozinaMnozinNetermu.keySet()) //najdu vsechny neterminaly prepsatelne na muj vybrany neterminal
            {
                if (mnozinaMnozinNetermu.get(klic).contains(neterm))
                    if (novaPravidla.containsKey(klic)) //a pridam patricne substituce !!! problem s ruzne dlouhzmi neterminaly se stejnym zacatkem...
                    {
                        novaPravidla.get(klic).addAll(pravaStrana);
                    } else
                    {
                        HashSet<ArrayList<String>> pomPrava = new HashSet();
                        pomPrava.addAll(pravaStrana);
                        novaPravidla.put(klic, pomPrava);
                    }
            }
        }
        String retS = "Pomocné množiny:\n";
        for (String klic : mnozinaMnozinNetermu.keySet())
        {
            retS += "N("+klic+") = {";
            for (String neterm : mnozinaMnozinNetermu.get(klic))
            {
                retS += neterm + ",";
            }
            retS = retS.substring(0, retS.length()-1);
            retS += "}\n";
        }
        retS += "\n";
        Gramatika retG = new Gramatika(new TreeSet(g.neterminaly), new TreeSet(g.terminaly), new String(g.koren), novaPravidla);
        retG.bezJednoduchych = true;
        retG.bezNepouzitelnych = false;
        Object[] ret = new Object[2];
        ret[0] = retG;
        ret[1] = retS;
        return ret;
    }

    private static TreeSet<String> jednoduche(Gramatika g, TreeSet<String> netermy)
    {
        TreeSet<String> ret = new TreeSet();
        for (String klic : netermy)
        {
            if (g.pravidla.containsKey(klic))
                for (ArrayList<String> pravidlo : g.pravidla.get(klic))
                {
                    if ((pravidlo.size() == 1)
                       && (!g.terminaly.contains(pravidlo.get(0)))
                       && (!pravidlo.get(0).equals("\u03B5")))
                        ret.add(pravidlo.get(0));
                }
        }
        return ret;
    }
}